//g++ mongohlp.cc -lboost_program_options
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <boost/functional/hash.hpp>
#include <google/sparse_hash_map>
#include <boost/program_options.hpp>
#include "client/dbclient.h"
using namespace std;
using namespace mongo;

namespace po = boost::program_options;
struct CmdLine { 
     CmdLine() : source_port(DefaultDBPort),dest_port(DefaultDBPort) { } 

     enum { 
          DefaultDBPort = 27017,
     };

     int source_port;
     int dest_port;

     string source_collection ;
     string dest_collection ;

     string source_server;
     string dest_server;
};
int parse_cmdline( CmdLine &cmd_line,int argc,char*argv[])
{
     bool error=false;
     boost::program_options::options_description options("command line options");
     boost::program_options::variables_map option_map;
     options.add_options() 
          ("help,h", "show this usage information")
          ("version", "show version information")
          ("sport", po::value<int>(&cmd_line.source_port), "specify source port number(default 27017)")
          ("dport", po::value<int>(&cmd_line.dest_port), "specify port number(default 27017)")
          ("source", po::value<string>(), "source server")
          ("dest", po::value<string>(), "source server")
          ("sc", po::value<string>(), "source collection")
          ("dc", po::value<string>(), "dest collection");
     try {
          boost::program_options::store( boost::program_options::parse_command_line(argc, argv, options), option_map);
          boost::program_options::notify(option_map);

          if (option_map.count("help")) {
               cout << options << endl;
          }
          const char *required[]={"source","dest","sc","dc"};
          const char *required_desc[]={"source server","dest server","source collection name","dest collection name"};
          string* params[]={&cmd_line.source_server,&cmd_line.dest_server,&cmd_line.source_collection,&cmd_line.dest_collection};
          for( size_t i=0 ; i< sizeof(required)/sizeof(char*); i++ ){
               if( !option_map.count(required[i]) ) {
                    error= true;
                    cout << required_desc[i] << " required" << endl;
               } else {
                    params[i]->append(option_map[required[i]].as<string>());
               }
          }
          if( error ){
               cout << options << endl;
          }
          if( option_map.count("sport") ) {
               cout << cmd_line.source_port << endl;
               if(!( cmd_line.source_port > 1024 && cmd_line.source_port < 65536) ){
                    cout << options << endl;
                    error = true;
               }
          }
          if( option_map.count("dport") ) {
               cout << cmd_line.dest_port<< endl;
               if(!( cmd_line.dest_port > 1024 && cmd_line.dest_port < 65536) ){
                    cout << options << endl;
                    error = true;
               }
          }
     } catch(po::error &e){
          cout << "ERROR: " << e.what() << endl << endl;
          cout << options << endl;
          return false;
     }
     return !error;

}
void copy_collection( CmdLine &cmd_line )
{
     int count = 0;
     BSONObj query = BSONObj();
     DBClientConnection src_conn;
     DBClientConnection dest_conn;
     char port[128];

     sprintf(port,"%s:%d",cmd_line.source_server.c_str(),cmd_line.source_port);
     cout << "from\t" << cmd_line.source_collection << "@" << port << endl; ;
     src_conn.connect(port); 

     sprintf(port,"%s:%d",cmd_line.dest_server.c_str(),cmd_line.dest_port);
     cout << "to\t" << cmd_line.dest_collection << "@" << port << endl;

     dest_conn.connect(port);

     BSONObj doc;
     auto_ptr<DBClientCursor> cursor = src_conn.query(cmd_line.source_collection, query);
     cout << "copying ..." << endl;
     while( cursor->more() )
     {
          doc = cursor->next();
          dest_conn.insert(cmd_line.dest_collection,doc);
          count++;
          if (count % 1000 == 0)
               cout << count << " copied" << endl;
     }
     cout << "total " << count << " copied" << endl;
}
int main (int argc, char* argv[])
{

     CmdLine cmd_line;
     if( parse_cmdline(cmd_line,argc,argv) ){
          copy_collection(cmd_line);
     }
     return 0;
}

